package com.capgemini.cn.authority.rest.service.impl;

import com.capgemini.cn.authority.data.entity.Authorities;
import com.capgemini.cn.authority.data.entity.Roles;
import com.capgemini.cn.authority.data.repository.AuthoritiesRepository;
import com.capgemini.cn.authority.data.repository.RolesRepository;
import com.capgemini.cn.authority.rest.exception.AuthRestBusinessException;
import com.capgemini.cn.authority.rest.service.AbstractBaseService;
import com.capgemini.cn.authority.rest.service.PermissionService;
import com.capgemini.cn.authority.rest.valueobject.DataResponse;
import com.capgemini.cn.authority.rest.valueobject.data.PermissionVO;
import lombok.Setter;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * Created at 2017/11/1
 *
 * @author Andriy
 */
@Service(value = PermissionServiceImpl.COMPONENT_NAME)
public class PermissionServiceImpl extends AbstractBaseService<PermissionVO, Authorities> implements PermissionService {

    public static final String COMPONENT_NAME = "permissionService";

    private final String[] IGNORE_PROPERTIES = {
            "roles",
            "assertsGroups"
    };

    @Autowired
    @Setter
    private AuthoritiesRepository authoritiesRepository;

    @Autowired
    @Setter
    private RolesRepository rolesRepository;

    @Transactional
    @Override
    public DataResponse<List<PermissionVO>> findAll(int page, int size, String orderProp, Sort.Direction direction) {
        return super.findAll(PermissionVO.class, page, size, orderProp, direction, this.IGNORE_PROPERTIES);
    }

    @Transactional
    @Override
    public DataResponse<PermissionVO> findById(long id) {
        return null;
    }

    @Transactional
    @Override
    public DataResponse<PermissionVO> add(PermissionVO source) {
        return null;
    }

    @Transactional
    @Override
    public boolean add(List<PermissionVO> sourceList) {
        return false;
    }

    @Transactional
    @Override
    public DataResponse<PermissionVO> update(long id, Map<String, Object> properties) throws AuthRestBusinessException {
        return null;
    }

    @Transactional
    @Override
    public boolean update(Map<String, Object> properties, List<PermissionVO> sourceList) {
        return false;
    }

    @Transactional
    @Override
    public DataResponse<List<PermissionVO>> findPermissionByRole(long roleId) {
        DataResponse<List<PermissionVO>> result = new DataResponse<>();
        Roles roleEntity = this.rolesRepository.findOne(roleId);
        if (ObjectUtils.isEmpty(roleEntity)) {
            throw new AuthRestBusinessException("无法根据主键ID（" + roleId + "）查询到对应的角色信息！");
        }
        List<PermissionVO> permissionVOList = super.conversionToValueObject(roleEntity.getAuthorities(), PermissionVO.class, this.IGNORE_PROPERTIES);
        result.setResponse(permissionVOList);
        return result;
    }

    @Transactional
    @Override
    public DataResponse<List<PermissionVO>> assignPermission(Long roleId, Long... permissionIds) throws AuthRestBusinessException {
        Roles roleEntity = this.rolesRepository.findOne(roleId);
        if (ObjectUtils.isEmpty(roleEntity))
            throw new AuthRestBusinessException("无法根据主键ID（" + roleId + "）查询到对应的角色实体对象信息！");
        List<Authorities> assignAuthorityList = this.authoritiesRepository.findAllByIdIn(permissionIds);
        if (ObjectUtils.isEmpty(assignAuthorityList))
            throw new AuthRestBusinessException("无法根据参数" + Arrays.toString(permissionIds) + "匹配到所有的权限信息，请确保需分配的权限信息正确！");
        List<Authorities> roleHasAuthorities = roleEntity.getAuthorities();
        if (!ObjectUtils.isEmpty(roleHasAuthorities)) {
            for (Authorities hasAuthority : roleHasAuthorities) {
                if (ArrayUtils.contains(permissionIds, hasAuthority.getId()))
                    throw new AuthRestBusinessException("当前角色已经拥有权限：" + hasAuthority.getAuthorityName() + "，权限主键ID值：" + hasAuthority.getId());
            }
        }
        roleEntity.getAuthorities().addAll(assignAuthorityList);
        Roles updatedRole = this.rolesRepository.saveAndFlush(roleEntity);
        return new DataResponse<List<PermissionVO>>().setResponse(super.conversionToValueObject(updatedRole.getAuthorities(), PermissionVO.class, this.IGNORE_PROPERTIES));
    }

    @Transactional
    @Override
    public DataResponse<List<PermissionVO>> releasePermission(Long roleId, Long... permissionIds) throws AuthRestBusinessException {
        Roles roleEntity = this.rolesRepository.findOne(roleId);
        if (ObjectUtils.isEmpty(roleEntity))
            throw new AuthRestBusinessException("无法根据主键ID（" + roleId + "）查询到对应的角色实体对象信息！");
        if (ObjectUtils.isEmpty(roleEntity.getAuthorities()))
            throw new AuthRestBusinessException("当前角色并未被分配任何权限！");
        List<Authorities> assignAuthorityList = this.authoritiesRepository.findAllByIdIn(permissionIds);
        if (ObjectUtils.isEmpty(assignAuthorityList))
            throw new AuthRestBusinessException("无法根据参数" + Arrays.toString(permissionIds) + "匹配到所有的权限信息，请确保需解绑的权限信息正确！");
        List<Authorities> needRemoveAuthorities = new ArrayList<>();
        for (Authorities hasAuthority : roleEntity.getAuthorities()) {
            if (ArrayUtils.contains(permissionIds, hasAuthority.getId())) {
                needRemoveAuthorities.add(hasAuthority);
            }
        }
        if (!CollectionUtils.isEmpty(needRemoveAuthorities)) {
            roleEntity.getAuthorities().removeAll(needRemoveAuthorities);
        }
        Roles updatedRole = this.rolesRepository.saveAndFlush(roleEntity);
        return new DataResponse<List<PermissionVO>>().setResponse(super.conversionToValueObject(updatedRole.getAuthorities(), PermissionVO.class, this.IGNORE_PROPERTIES));
    }
}
